﻿using LogSystem;
using System;
using System.Collections.Generic;
using Extensions;
using UnityEngine;
using UnityEngine.Profiling;
using Yoozoo.Core.Extensions.Engine;
using Yoozoo.Mars.Got;

namespace Yoozoo.Gameplay.City
{
    public class CityRealHudManager : MonoBehaviour
    {
        private CityRealAiConfigManager _cfgMgr;

        // 普通气泡 (如：心情、顾客前往房间、商品收费等)
        public Dictionary<int, HudNpcBubble> HudDic { get; private set; }
        
        // 技能气泡（如：点燃激情飘字）
        public Dictionary<int, HudNpcBubble> SkillHudDic { get; private set; }

        // 进度条气泡（如：顾客消费进度、排队心情条）
        public Dictionary<int, HudNpcProgressBar> ProgressBarDic { get; private set; }

        // 商品气泡（如：顾客购买商品）
        public Dictionary<int, HudCommodityBubble> CommodityDic { get; private set; }
        
        // 雇佣气泡
        public Dictionary<int, HudStaffBubble> StaffDic { get; private set; }
        
        // 美女心情气泡
        public Dictionary<int, HudBabeMoodBubble> BabeMoodDic { get; private set; }
        
        // 特效（如：顾客爱心、心碎）
        public Dictionary<int, HudEffect> EffectDic { get; private set; }
        
        // 对话气泡
        public Dictionary<int, HudDialogueBubble> DialogueDic { get; private set; }
        
        private int _updateIndex = 0;

        public Transform hudRoot;
        public Transform effectRoot;

        public void OnInitialize(CityRealAiConfigManager cfgMgr)
        {
            _cfgMgr = cfgMgr;
            HudDic = new Dictionary<int, HudNpcBubble>();
            SkillHudDic = new Dictionary<int, HudNpcBubble>(0);
            ProgressBarDic = new Dictionary<int, HudNpcProgressBar>();
            CommodityDic = new Dictionary<int, HudCommodityBubble>(0);
            StaffDic = new Dictionary<int, HudStaffBubble>();
            BabeMoodDic = new Dictionary<int, HudBabeMoodBubble>();
            EffectDic = new Dictionary<int, HudEffect>();
            DialogueDic = new Dictionary<int, HudDialogueBubble>();

            {
                var go = new GameObject("HUD");
                hudRoot = go.transform;
                hudRoot.SetParent(transform);
                hudRoot.localScale = CityRealAiConst.HudScale;
            }
            {
                var go = new GameObject("Effect");
                effectRoot = go.transform;
                effectRoot.SetParent(transform);
            }
        }

        //=========================气泡=============start=========================

        #region 气泡

        public void OnShowHud(int uid, Transform roleTran, string bubble, float displaytTime = -1,
            int bone_bind = 0, int event_id = 0, string stringParam = null, int intParam = 0)
        {
            if (!HudDic.TryGetValue(uid, out var hudNpcEvent))
            {
                hudNpcEvent = new HudNpcBubble(uid, this, _cfgMgr);
                HudDic.Add(uid, hudNpcEvent);
            }

            hudNpcEvent.OnChangeHud(uid, roleTran, bubble, displaytTime, bone_bind, event_id, stringParam, intParam);
        }

        public void OnStopHud(int uid)
        {
            if (HudDic.TryGetValue(uid, out var hud))
            {
                hud.OnStopHud();
            }
        }

        public void OnReShowHud(int uid)
        {
            if (HudDic.TryGetValue(uid, out var hud))
            {
                hud.OnReShowHud();
            }
        }

        public void OnHideHud(int uid)
        {
            if (HudDic.TryGetValue(uid, out var hud))
            {
                hud.OnHideHud();
            }
        }
        
        public bool IsExistHud(int uid)
        {
            if (HudDic.TryGetValue(uid, out var hud))
            {
                return hud.IsExistHud;
            }

            return false;
        }

        #endregion

        //=========================气泡=============end=========================
        
        //=========================技能气泡=============start=========================

        #region 技能气泡

        public void OnShowSkillHud(int uid, Transform roleTran, string bubble, float displaytTime = -1,
            int bone_bind = 0, int event_id = 0, string stringParam = null, int intParam = 0)
        {
            if (!SkillHudDic.TryGetValue(uid, out var hudNpcEvent))
            {
                hudNpcEvent = new HudNpcBubble(uid, this, _cfgMgr);
                SkillHudDic.Add(uid, hudNpcEvent);
            }

            hudNpcEvent.OnChangeHud(uid, roleTran, bubble, displaytTime, bone_bind, event_id, stringParam, intParam);
        }

        public void OnStopSkillHud(int uid)
        {
            if (SkillHudDic.TryGetValue(uid, out var hud))
            {
                hud.OnStopHud();
            }
        }

        public void OnReShowSkillHud(int uid)
        {
            if (SkillHudDic.TryGetValue(uid, out var hud))
            {
                hud.OnReShowHud();
            }
        }

        public void OnHideSkillHud(int uid)
        {
            if (SkillHudDic.TryGetValue(uid, out var hud))
            {
                hud.OnHideHud();
            }
        }

        #endregion

        //=========================技能气泡=============end=========================

        //=========================进度条=============start=========================

        #region 进度条

        public void OnShowProgressBar(int uid, string bubble, float duration, Transform roleTran,
            int bind_bone = 0)
        {
            if (duration <= 0)
            {
                return;
            }

            if (!ProgressBarDic.TryGetValue(uid, out var hudNpcProgressBar))
            {
                hudNpcProgressBar = new HudNpcProgressBar(uid, this, _cfgMgr);
                ProgressBarDic.Add(uid, hudNpcProgressBar);
            }

            hudNpcProgressBar.OnChangeProgressBar(uid, bubble, duration, roleTran, bind_bone);
        }

        public void OnStopProgressBar(int uid)
        {
            if (ProgressBarDic.TryGetValue(uid, out var hudNpcProgressBar))
            {
                hudNpcProgressBar.OnStopHud();
            }
        }

        public void OnReShowProgressBar(int uid)
        {
            if (ProgressBarDic.TryGetValue(uid, out var hudNpcProgressBar))
            {
                hudNpcProgressBar.OnReShowHud();
            }
        }

        public void OnHideProgressBar(int uid)
        {
            if (ProgressBarDic.TryGetValue(uid, out var hudNpcProgressBar))
            {
                hudNpcProgressBar.OnHideHud();
            }
        }
        
        public bool IsExistProgressBar(int uid)
        {
            if (ProgressBarDic.TryGetValue(uid, out var hudNpcProgressBar))
            {
                return hudNpcProgressBar.IsExistHud;
            }

            return false;
        }

        #endregion

        //=========================进度条=============end=========================
        
        //=========================商品气泡=============start=========================

        #region 商品气泡

        public void OnShowCommodity(int uid, string bubble, Transform roleTran, int bind_bone = 0, int commodityId = 0, bool isSuperCustomer = false)
        {
            if (!CommodityDic.TryGetValue(uid, out var hudCommodityBubble))
            {
                hudCommodityBubble = new HudCommodityBubble(uid, this, _cfgMgr);
                CommodityDic.Add(uid, hudCommodityBubble);
            }

            hudCommodityBubble.OnChangeCommodityBubble(uid, bubble, roleTran, bind_bone, commodityId, isSuperCustomer);
        }

        public void OnSimulationClickCommodityHUD(int uid)
        {
            if (CommodityDic.TryGetValue(uid, out var hudCommodityBubble))
            {
                hudCommodityBubble.OnSimulationClickCommodityHUD();
            }
        }

        public void OnUpdateComodityPerformer(int uid, int performerUid)
        {
            if (CommodityDic.TryGetValue(uid, out var hudCommodityBubble))
            {
                hudCommodityBubble.OnUpdatePerformerUid(performerUid);
            }
        }
        
        public void PlayProgressAndHideCommodityBubble(int uid, float duration)
        {
            if (CommodityDic.TryGetValue(uid, out var hudCommodityBubble))
            {
                hudCommodityBubble.PlayProgressAndHideCommodityBubble(duration);
            }
        }

        public void OnStopCommodity(int uid)
        {
            if (CommodityDic.TryGetValue(uid, out var hudCommodityBubble))
            {
                hudCommodityBubble.OnStopHud();
            }
        }

        public void OnReShowCommodity(int uid)
        {
            if (CommodityDic.TryGetValue(uid, out var hudCommodityBubble))
            {
                hudCommodityBubble.OnReShowHud();
            }
        }

        public void OnHideCommodity(int uid)
        {
            if (CommodityDic.TryGetValue(uid, out var hudCommodityBubble))
            {
                hudCommodityBubble.OnHideHud();
            }
        }

        /// <summary>
        /// 是否存在商品hud
        /// </summary>
        /// <param name="uid"></param>
        /// <param bubbleId="bubbleId">检测当前气泡是否需要气泡类型</param>
        /// <param isCheckPerformer="isCheckPerformer">检测当前气泡是否存在去触发该气泡的服务员</param>
        /// <returns></returns>
        public bool IsExistCommodityHud(int uid, int bubbleType = 0, bool isCheckPerformer = false)
        {
            if (CommodityDic.TryGetValue(uid, out var hudCommodityBubble))
            {
                return hudCommodityBubble.IsExistHud && (bubbleType == 0 || hudCommodityBubble.CommodityType == bubbleType) && (!isCheckPerformer || hudCommodityBubble.PerformerUid <= 0);
            }

            return false;
        }

        #endregion

        //=========================商品气泡=============end=========================
        
        //=========================雇佣气泡=============start=========================

        #region 雇佣气泡

        public void OnShowStaff(int uid, string bubble, Transform roleTran,int staffId, int bind_bone = 0)
        {
            if (!StaffDic.TryGetValue(uid, out var hudStaffBubble))
            {
                hudStaffBubble = new HudStaffBubble(uid, this, _cfgMgr);
                StaffDic.Add(uid, hudStaffBubble);
            }

            hudStaffBubble.OnChangeStaffBubble(uid, bubble, roleTran, bind_bone, staffId);
        }

        public void OnStopStaff(int uid)
        {
            if (StaffDic.TryGetValue(uid, out var hudStaffBubble))
            {
                hudStaffBubble.OnStopHud();
            }
        }

        public void OnReShowStaff(int uid, string bubble, Transform roleTran,int staffId, int bind_bone = 0)
        {
            if (StaffDic.TryGetValue(uid, out var hudStaffBubble))
            {
                hudStaffBubble.OnReShowHud();
            }
            else if(staffId > 0 && !string.IsNullOrEmpty(bubble))
            {
                OnShowStaff(uid, bubble, roleTran, staffId, bind_bone);
            }
        }

        public void OnHideStaff(int uid)
        {
            if (StaffDic.TryGetValue(uid, out var hudStaffBubble))
            {
                hudStaffBubble.OnHideHud();
            }
        }

        #endregion

        //=========================雇佣气泡=============end=========================
        
        //=========================美女资源气泡=============start=========================

        #region 美女资源气泡

        public void OnShowBabeMood(int uid, string bubble, Transform roleTran,int resId, int bind_bone = 0)
        {
            if (!BabeMoodDic.TryGetValue(uid, out var hudBabeMoodBubble))
            {
                hudBabeMoodBubble = new HudBabeMoodBubble(uid, this, _cfgMgr);
                BabeMoodDic.Add(uid, hudBabeMoodBubble);
            }

            hudBabeMoodBubble.OnChangeBabeMoodBubble(uid, bubble, roleTran, bind_bone, resId);
        }

        public void OnStopBabeMood(int uid)
        {
            if (BabeMoodDic.TryGetValue(uid, out var hudBabeMoodBubble))
            {
                hudBabeMoodBubble.OnStopHud();
                BabeMoodDic.Remove(uid);
            }
        }

        public void OnReShowBabeMood(int uid)
        {
            if (BabeMoodDic.TryGetValue(uid, out var hudBabeMoodBubble))
            {
                hudBabeMoodBubble.OnReShowHud();
            }
        }

        public void OnHideBabeMood(int uid)
        {
            if (BabeMoodDic.TryGetValue(uid, out var hudBabeMoodBubble))
            {
                hudBabeMoodBubble.OnHideHud();
            }
        }
        
        public bool IsExistBabeMood(int uid)
        {
            if (BabeMoodDic.TryGetValue(uid, out var hudBabeMoodBubble))
            {
                return hudBabeMoodBubble.IsExistHud;
            }

            return false;
        }

        #endregion

        //=========================美女资源气泡=============end=========================
        
        //=========================特效=============start=========================

        #region 特效

        public void OnShowEffect(int uid, Transform roleTran, string bubble, float displaytTime = -1, int bone_bind = 0)
        {
            if (!EffectDic.TryGetValue(uid, out var hudEffect))
            {
                hudEffect = new HudEffect(uid, this, _cfgMgr);
                EffectDic.Add(uid, hudEffect);
            }

            hudEffect.OnChangeHud(uid, roleTran, bubble, displaytTime, bone_bind);
        }

        public void OnStopEffect(int uid)
        {
            if (EffectDic.TryGetValue(uid, out var hud))
            {
                hud.OnStopHud();
            }
        }

        public void OnReShowEffect(int uid)
        {
            if (EffectDic.TryGetValue(uid, out var hud))
            {
                hud.OnReShowHud();
            }
        }

        public void OnHideEffect(int uid)
        {
            if (EffectDic.TryGetValue(uid, out var hud))
            {
                hud.OnHideHud();
            }
        }

        #endregion

        //=========================特效=============end=========================
        
        //=========================对话气泡=============start=========================

        #region 对话气泡

        public void OnShowDialogue(int uid, string bubble, Transform roleTran,int areaId, float displaytTime = -1, int bind_bone = 0)
        {
            if (!DialogueDic.TryGetValue(uid, out var hudDialogueBubble))
            {
                hudDialogueBubble = new HudDialogueBubble(uid, this, _cfgMgr);
                DialogueDic.Add(uid, hudDialogueBubble);
            }

            hudDialogueBubble.OnChangeDialogueBubble(uid, bubble, roleTran, bind_bone, areaId, displaytTime);
        }

        public void OnStopDialogue(int uid)
        {
            if (DialogueDic.TryGetValue(uid, out var hudDialogueBubble))
            {
                hudDialogueBubble.OnStopHud();
            }
        }

        public void OnReShowDialogue(int uid)
        {
            if (DialogueDic.TryGetValue(uid, out var hudDialogueBubble))
            {
                hudDialogueBubble.OnReShowHud();
            }
        }

        public void OnHideDialogue(int uid)
        {
            if (DialogueDic.TryGetValue(uid, out var hudDialogueBubble))
            {
                hudDialogueBubble.OnHideHud();
            }
        }

        #endregion

        //=========================对话气泡=============end=========================
        
        public void SetHudColliderState(int uid, bool state)
        {
            if (StaffDic.TryGetValue(uid, out var hudStaffBubble))
            {
                hudStaffBubble.SetColliderState(state);
            }
        }
        public void GetHudObj(string path, Transform parent, Action<GameObject> complete, bool autoActive = true)
        {
            CityRealAiManager.GetInstance().Pop(path, (asset) =>
            {
                var hudObj = asset;
                hudObj.transform.localScale = Vector3.one;
                hudObj.SetParent(parent);
                complete?.Invoke(hudObj);
            }, autoActive);
        }

        private void Update()
        {
            var index = 0;
            foreach (var keyValuePair in HudDic)
            {
                // if (index % CityRealAiConst.HudUpdateInterval == _updateIndex)
                {
                    keyValuePair.Value.OnUpdatePosition();
                }
                // index++;
            }
            
            foreach (var keyValuePair in SkillHudDic)
            {
                // if (index % CityRealAiConst.HudUpdateInterval == _updateIndex)
                {
                    keyValuePair.Value.OnUpdatePosition();
                }
                // index++;
            }

            foreach (var keyValuePair in ProgressBarDic)
            {
                // if (index % CityRealAiConst.HudUpdateInterval == _updateIndex)
                {
                    keyValuePair.Value.OnUpdatePosition();
                }
                // index++;
            }
            
            foreach (var keyValuePair in CommodityDic)
            {
                // if (index % CityRealAiConst.HudUpdateInterval == _updateIndex)
                {
                    keyValuePair.Value.OnUpdatePosition();
                }
                // index++;
            }
            foreach (var keyValuePair in StaffDic)
            {
                // if (index % CityRealAiConst.HudUpdateInterval == _updateIndex)
                {
                    keyValuePair.Value.OnUpdatePosition();
                }
                // index++;
            }
            
            foreach (var keyValuePair in BabeMoodDic)
            {
                // if (index % CityRealAiConst.HudUpdateInterval == _updateIndex)
                {
                    keyValuePair.Value.OnUpdatePosition();
                }
                // index++;
            }
            
            foreach (var keyValuePair in DialogueDic)
            {
                // if (index % CityRealAiConst.HudUpdateInterval == _updateIndex)
                {
                    keyValuePair.Value.OnUpdatePosition();
                }
                // index++;
            }

            // _updateIndex++;
            // if (_updateIndex == CityRealAiConst.HudUpdateInterval)
            // {
            //     _updateIndex = 0;
            // }
        }

        public void DestroyHudObj(string resPath, GameObject hudObj)
        {
            CityRealAiManager.GetInstance().Push(resPath, hudObj);
        }

        public void OnReset()
        {
            if (StaffDic != null)
            {
                foreach (var keyValuePair in StaffDic)
                {
                    keyValuePair.Value.OnDispose();
                }
                StaffDic.Clear();
            }
            
            if (BabeMoodDic != null)
            {
                foreach (var keyValuePair in BabeMoodDic)
                {
                    keyValuePair.Value.OnDispose();
                }
                BabeMoodDic.Clear();
            }
            
            if (HudDic != null)
            {
                foreach (var keyValuePair in HudDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                HudDic.Clear();
            }
            
            if (SkillHudDic != null)
            {
                foreach (var keyValuePair in SkillHudDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                SkillHudDic.Clear();
            }

            if (ProgressBarDic != null)
            {
                foreach (var keyValuePair in ProgressBarDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                ProgressBarDic.Clear();
            }
            
            if (CommodityDic != null)
            {
                foreach (var keyValuePair in CommodityDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                CommodityDic.Clear();
            }
            
            if (EffectDic != null)
            {
                foreach (var keyValuePair in EffectDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                EffectDic.Clear();
            }
        }

        public void OnDispose()
        {
            if (HudDic != null)
            {
                foreach (var keyValuePair in HudDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                HudDic.Clear();
                HudDic = null;
            }
            
            if (BabeMoodDic != null)
            {
                foreach (var keyValuePair in BabeMoodDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                BabeMoodDic.Clear();
                BabeMoodDic = null;
            }
            
            if (SkillHudDic != null)
            {
                foreach (var keyValuePair in SkillHudDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                SkillHudDic.Clear();
                SkillHudDic = null;
            }

            if (ProgressBarDic != null)
            {
                foreach (var keyValuePair in ProgressBarDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                ProgressBarDic.Clear();
                ProgressBarDic = null;
            }
            
            if (CommodityDic != null)
            {
                foreach (var keyValuePair in CommodityDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                CommodityDic.Clear();
                CommodityDic = null;
            }
            if (StaffDic != null)
            {
                foreach (var keyValuePair in StaffDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                StaffDic.Clear();
                StaffDic = null;
            }
            
            if (EffectDic != null)
            {
                foreach (var keyValuePair in EffectDic)
                {
                    keyValuePair.Value.OnDispose();
                }

                EffectDic.Clear();
                EffectDic = null;
            }

            Destroy(this);
        }
    }

    public class HudNpcBase
    {
        public int Uid { get; }

        protected bool IsInLoadHud = false;

        public bool IsExistHud
        {
            get
            {
                if (_hudObj != null)
                {
                    return true;
                }

                return IsInLoadHud;
            }
        }

        public bool IsInHideAni { get; private set; }

        protected CityRealHudManager _hudMgr;
        protected CityRealAiConfigManager _cfgMgr;
        protected Transform _roleTran;
        protected Transform _boneTran;
        protected GameObject _hudObj;
        protected BoxCollider _hudCollider;
        protected string _hudResPath;

        protected string startAnimName;
        protected string endAnimName;
        protected string hideAnimName;
        protected bool _isStop = false;

        public HudNpcBase(int uid, CityRealHudManager hudMgr, CityRealAiConfigManager cfgMgr)
        {
            Uid = uid;
            _hudMgr = hudMgr;
            _cfgMgr = cfgMgr;
        }

        protected virtual void OnChangeHud(Transform roleTran)
        {
            _roleTran = roleTran;

            if (IsExistHud)
            {
                OnHideHud();
            }
            else
            {
                TryShowHud();
            }
        }

        protected virtual void TryShowHud()
        {
        }

        public void OnStopHud()
        {
            if (!IsExistHud)
            {
                return;
            }

            _isStop = true;
            if (_hudObj != null)
            {
                _hudObj.SetActive(false);
            }
        }

        public void OnReShowHud()
        {
            if (!IsExistHud)
            {
                return;
            }
            
            _isStop = false;
            if (_hudObj != null)
            {
                TryShowHudAnimation();
                _hudObj.SetActive(true);
            }
        }

        public void OnUpdatePosition()
        {
            if (!IsExistHud)
            {
                return;
            }

            if (_hudObj != null && _boneTran != null)
            {
                var bonePos = _boneTran.position;
                var worldPos = new Vector3(bonePos.x + CityRealAiConst.HudXOffset,
                    bonePos.y + CityRealAiConst.HudYOffset, bonePos.z + CityRealAiConst.HudZOffset);
                _hudObj.transform.position = worldPos;
            }
        }

        protected void OnDelayHideHud(object param)
        {
            OnHideHud();
        }

        public virtual void OnHideHud()
        {
            if (IsInHideAni)
            {
                return;
            }

            if (_hudObj != null)
            {
                var ani = _hudObj.GetComponent<Animation>();
                if (ani == null)
                {
                    DestroyHud();
                }
                else
                {
                    if (!string.IsNullOrEmpty(this.endAnimName))
                    {
                        IsInHideAni = true;
                        ani.Play(this.endAnimName);
                        Timers.inst.Add(0.5f, 1, HideHudCallback);
                    }
                    else
                    {
                        DestroyHud();
                    }
                }
            }
            else
            {
                TryShowHud();
            }
        }

        protected void HideHudCallback(object param)
        {
            IsInHideAni = false;
            DestroyHud();
            TryShowHud();
        }

        protected virtual void DestroyHud()
        {
            if (_hudMgr != null && _hudObj != null)
            {
                _hudMgr.DestroyHudObj(_hudResPath, _hudObj);
                _hudObj = null;
            }
            IsInLoadHud = false;
        }

        public void OnDispose()
        {
            IsInHideAni = false;
            Timers.inst.Remove(HideHudCallback);
            Timers.inst.Remove(OnDelayHideHud);
            DestroyHud();
            _hudMgr = null;
            _roleTran = null;
            _boneTran = null;
            _cfgMgr = null;
        }
        
        
        protected void TryShowHudAnimation()
        {
            var ani = _hudObj.GetComponent<Animation>();
            if (ani)
            {
                {
                    if (!string.IsNullOrEmpty(this.startAnimName))
                    {
                        ani.Play(this.startAnimName);
                    }
                }
            }
        }

        public void SetColliderState(bool state)
        {
            if (_hudCollider)
            {
                _hudCollider.enabled = state;
            }
        }
    }

    public class HudNpcProgressBar : HudNpcBase
    {
        private CityRealHudBubbleData _nextBubbleData;

        public HudNpcProgressBar(int uid, CityRealHudManager hudMgr, CityRealAiConfigManager cfgMgr) : base(uid, hudMgr, cfgMgr)
        {
        }

        public void OnChangeProgressBar(int uid, string bubble, float duration, Transform roleTran, int bind_bone)
        {
            _nextBubbleData.SetValue(uid, string.Format(CityRealAiConst.BubblePath, bubble), duration, bind_bone);
            base.OnChangeHud(roleTran);
        }

        protected override void TryShowHud()
        {
            if (_nextBubbleData.inUse)
            {
                CityRealHudBubbleData bubbleData = _nextBubbleData;
                _nextBubbleData.Reset();
                if (bubbleData.bones_bind <= 0)
                {
                    Debug.LogError(LogModule.CityAI, "尝试显示进度条 但bones_bind_bubble = 0");
                    return;
                }

                var cfg = _cfgMgr.GetBonePathConfig(bubbleData.bones_bind);
                if (cfg.id == _cfgMgr.EmptyBonePathCfg.id || string.IsNullOrEmpty(cfg.bone_path))
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示进度条，但是配置 city_ai_npc_bonepath 中未找到 id = {0} 的配置", bubbleData.bones_bind);
                    return;
                }

                string bonePath = cfg.bone_path;
                _boneTran = _roleTran.Find(bonePath);
                if (_boneTran == null)
                {
                    bonePath = bonePath.Substring(bonePath.LastIndexOf("/") + 1);
                    if(string.Equals(bonePath, "Root"))
                    {
                        _boneTran = _roleTran;                 
                    }
                    else
                    {
                        _boneTran = _roleTran.Find(bonePath);
                    }
                }

                if (_boneTran == null)
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示进度条，但是模型中 未找到 BonePath = {0} 的节点", cfg.bone_path);
                    return;
                }

                float duration = bubbleData.displayTime;
                _hudResPath = bubbleData.prefabPath;
                IsInLoadHud = true;
                _hudMgr.GetHudObj(_hudResPath, _hudMgr.hudRoot, (hudObj) =>
                {
                    _hudObj = hudObj;
                    IsInLoadHud = false;
                    CityRealAiProgressBarHUD progressBarHUD = _hudObj.GetComponent<CityRealAiProgressBarHUD>();
                    if (progressBarHUD)
                    {
                        progressBarHUD.Uid = bubbleData.uid;
                        progressBarHUD.RoleTrans = _roleTran;
                        progressBarHUD.SetProgressBar(duration);
                        this.startAnimName = progressBarHUD.StartAnimationName;
                        this.endAnimName = progressBarHUD.EndAnimationName;
                        this.hideAnimName = progressBarHUD.HideAnimationName;
                    }
                    TryShowHudAnimation();

                    _hudObj.transform.position = new Vector3(-1000f, -1000f, -1000f);
                    _hudObj.transform.localEulerAngles = new Vector3(45, -10, 0);
// #if UNITY_EDITOR
//                     _hudObj.name = $"duration = {duration} 时长的进度条";
// #endif
                    if (duration > 0) // 时间到了自动消失
                    {
                        Timers.inst.Add(duration, 1, OnDelayHideHud);
                    }
                    // 屋顶显示时 / 已停止时 不显示气泡
                    bool isNotVisible = (CityRealAiManager.GetInstance().RoofShowState && CityRealAiManager.GetInstance().LimitShowState);
                    if (isNotVisible || _isStop)
                    {
                        if (_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(false);
                        }
                    }
                    else
                    {
                        if (!_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(true);
                        }
                    }
                }, false);

                bubbleData.Reset();
            }
        }
    }

    public class HudNpcBubble : HudNpcBase
    {
        private CityRealHudBubbleData _nextBubbleData;
        private CityRealHudBubbleData _currentBubbleData;
        private TimerCallback onDelayHideHud;
        private Action<GameObject> onGetHudObjCompleted;
        private Dictionary<string, string> assetMap = new Dictionary<string, string>(8);

        private string GetBubbleAssetPath(string assetName)
        {
            if (string.IsNullOrEmpty(assetName))
            {
                Debug.LogError($"GetBubbleAssetPath = {assetName}");
                return "";
            }
            
            if (assetMap.TryGetValue(assetName, out string assetPath))
            {
                return assetPath;
            }

            assetPath = string.Format(CityRealAiConst.BubblePath, assetName);
            assetMap[assetName] = assetPath;
            return assetPath;
        }

        public HudNpcBubble(int uid, CityRealHudManager hudMgr, CityRealAiConfigManager cfgMgr) : base(uid, hudMgr, cfgMgr)
        {
            onDelayHideHud = OnDelayHideHud;
            onGetHudObjCompleted = OnGetHudObjCompleted;
        }

        public void OnChangeHud(int uid, Transform roleTran, string bubble, float displaytTime, int bone_bind,
            int event_id, string stringParam, int intParam)
        {
            _nextBubbleData.SetValue(uid, GetBubbleAssetPath(bubble), displaytTime, bone_bind, event_id, stringParam, intParam);
            base.OnChangeHud(roleTran);
        }

        protected override void TryShowHud()
        {
            Profiler.BeginSample("HudNpcBubble.TryShowHud");
            if (_nextBubbleData.inUse)
            {
                _currentBubbleData = _nextBubbleData;
                _nextBubbleData.Reset();
                if (_currentBubbleData.bones_bind <= 0)
                {
                    // Debug.LogError(LogModule.CityAI, "尝试触发 OnShowBubble事件，但是配置 city_ai_event 中 bones_bind_bubble = 0");
                    return;
                }

                var cfg = _cfgMgr.GetBonePathConfig(_currentBubbleData.bones_bind);
                if (cfg.id == _cfgMgr.EmptyBonePathCfg.id || string.IsNullOrEmpty(cfg.bone_path))
                {
                    // Debug.LogErrorFormat(LogModule.CityAI,
                    //     LogLevelType.Develop, "尝试触发 OnShowBubble事件，但是配置 city_ai_npc_bonepath 中未找到 id = {0} 的配置",
                    //     _currentBubbleData.bones_bind);
                    return;
                }

                string bonePath = cfg.bone_path;
                _boneTran = _roleTran.Find(bonePath);
                if (_boneTran == null)
                {
                    bonePath = bonePath.Substring(bonePath.LastIndexOf("/") + 1);
                    if (string.Equals(bonePath, "Root"))
                    {
                        _boneTran = _roleTran;
                    }
                    else
                    {
                        _boneTran = _roleTran.Find(bonePath);
                    }
                }

                if (_boneTran == null)
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, "尝试触发 OnShowBubble事件，但是模型中 未找到 BonePath = {0} 的节点",
                    //     LogLevelType.Develop, cfg.bone_path);
                    _boneTran = _roleTran;
                    // return;
                }

                _hudResPath = _currentBubbleData.prefabPath;
                IsInLoadHud = true;
                _hudMgr.GetHudObj(_hudResPath, _hudMgr.hudRoot, onGetHudObjCompleted, false);
            }
            Profiler.EndSample();
        }

        private void OnGetHudObjCompleted(GameObject hudObj)
        {
            _hudObj = hudObj;
            IsInLoadHud = false;
            CityRealAiHUDBase hudBase = _hudObj.GetComponent<CityRealAiHUDBase>();
            if (hudBase)
            {
                hudBase.Uid = _currentBubbleData.uid;
                hudBase.RoleTrans = _roleTran;
                this.startAnimName = hudBase.StartAnimationName;
                this.endAnimName = hudBase.EndAnimationName;
                this.hideAnimName = hudBase.HideAnimationName;

                if (hudBase is CityRealAiCommodityCostHUD)
                {
                    CityRealAiCommodityCostHUD commodityCostHUD = hudBase as CityRealAiCommodityCostHUD;
                    commodityCostHUD.SetCostText(_currentBubbleData.stringParam);
                }
                else if (hudBase is CityRealAiLightPassionHUD)
                {
                    CityRealAiLightPassionHUD lightPassionHUD = hudBase as CityRealAiLightPassionHUD;
                    lightPassionHUD.SetCostText(_currentBubbleData.param2, _currentBubbleData.displayTime);
                }
            }

            TryShowHudAnimation();

            // var root = _hudObj.transform.Find("Root");
            // if (root != null)
            // {
            //     var scaleCtrl = root.GetOrAddCompoment<HUDScaleControl>();
            //     scaleCtrl.SetInitScale(1, 1, 1);
            // }
            _hudObj.transform.position = new Vector3(-1000f, -1000f, -1000f);
            _hudObj.transform.localEulerAngles = new Vector3(45, -10, 0);
#if UNITY_EDITOR && !ENABLE_PROFILER
            _hudObj.name = $"ui = {_currentBubbleData.uid.ToString()} eventId = {_currentBubbleData.eventId.ToString()} 产生的AI气泡";
#endif
            float duration = _currentBubbleData.displayTime;
            if (duration > 0) // 时间到了自动消失
            {
                Timers.inst.Add(duration, 1, onDelayHideHud);
            }

            // 屋顶显示时 / 已停止时 不显示气泡
            bool isNotVisible = (CityRealAiManager.GetInstance().RoofShowState && CityRealAiManager.GetInstance().LimitShowState);
            if (isNotVisible || _isStop)
            {
                if (_hudObj.activeSelf)
                {
                    _hudObj.SetActive(false);
                }
            }
            else
            {
                if (!_hudObj.activeSelf)
                {
                    _hudObj.SetActive(true);
                }
            }
        }
    }
    
    public class HudCommodityBubble : HudNpcBase
    {
        private CityRealHudBubbleData _nextBubbleData;

        private CityRealAiCommodityHUD _commodityHUD;

        public int CommodityType
        {
            get
            {
                if (_commodityHUD == null)
                {
                    return 0;
                }

                return _commodityHUD.CommodityType;
            }
        }
        
        public int PerformerUid { get; private set; }

        public HudCommodityBubble(int uid, CityRealHudManager hudMgr, CityRealAiConfigManager cfgMgr) : base(uid, hudMgr, cfgMgr)
        {
        }

        public void OnSimulationClickCommodityHUD()
        {
            if (!IsExistHud)
            {
                return;
            }
            
            CityRealAiCSharpCallLuaManager.OnSimulationClickCommodityHUD(_commodityHUD.Button);
        }

        public void OnChangeCommodityBubble(int uid, string bubble, Transform roleTran, int bind_bone, int commodityId, bool isSuperCustomer)
        {
            _nextBubbleData.SetValue(uid, string.Format(CityRealAiConst.BubblePath, bubble), 0, bind_bone, commodityId:commodityId, isSuperCustomer:isSuperCustomer);
            base.OnChangeHud(roleTran);
        }

        public void OnUpdatePerformerUid(int uid)
        {
            if (!IsExistHud)
            {
                PerformerUid = 0;
                return;
            }

            PerformerUid = uid;
        }

        public void PlayProgressAndHideCommodityBubble(float duration)
        {
            if (_commodityHUD)
            {
                _commodityHUD.SetProgressBar(duration);
                if (!string.IsNullOrEmpty(_commodityHUD.FinishAnimationName))
                {
                    this.endAnimName = _commodityHUD.FinishAnimationName;
                }
                if (duration > 0) // 时间到了自动消失
                {
                    Timers.inst.Add(duration, 1, OnDelayHideHud);
                }
                else
                {
                    OnDelayHideHud(null);
                }
            }
        }

        protected override void TryShowHud()
        {
            if (_nextBubbleData.inUse)
            {
                CityRealHudBubbleData bubbleData = _nextBubbleData;
                _nextBubbleData.Reset();
                if (bubbleData.bones_bind <= 0)
                {
                    Debug.LogError(LogModule.CityAI, "尝试显示商品气泡 但bones_bind_bubble = 0");
                    return;
                }

                var cfg = _cfgMgr.GetBonePathConfig(bubbleData.bones_bind);
                if (cfg.id == _cfgMgr.EmptyBonePathCfg.id || string.IsNullOrEmpty(cfg.bone_path))
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示商品气泡，但是配置 city_ai_npc_bonepath 中未找到 id = {0} 的配置", bubbleData.bones_bind);
                    return;
                }

                string bonePath = cfg.bone_path;
                _boneTran = _roleTran.Find(bonePath);
                if (_boneTran == null)
                {
                    bonePath = bonePath.Substring(bonePath.LastIndexOf("/") + 1);
                    if (string.Equals(bonePath, "Root"))
                    {
                        _boneTran = _roleTran;
                    }
                    else
                    {
                        _boneTran = _roleTran.Find(bonePath);
                    }
                }

                if (_boneTran == null)
                {
                    _boneTran = _roleTran;
                    // Debug.LogErrorFormat(LogModule.CityAI, "尝试触发 显示商品气泡，但是模型中 未找到 BonePath = {0} 的节点",
                    //     LogLevelType.Develop, cfg.bone_path);
                    // return;
                }

                int uid = bubbleData.uid;
                _hudResPath = bubbleData.prefabPath;
                int commodityId = bubbleData.commodityId;
                bool isSuperCustomer = bubbleData.isSuperCustomer;
                IsInLoadHud = true;
                _hudMgr.GetHudObj(_hudResPath, _hudMgr.hudRoot, (hudObj) =>
                {
                    _hudObj = hudObj;
                    IsInLoadHud = false;
                    float duration = 0;
                    CityRealAiCommodityHUD commodityHUD = _hudObj.GetComponent<CityRealAiCommodityHUD>();
                    _commodityHUD = commodityHUD;
                    if (commodityHUD)
                    {
                        commodityHUD.Uid = uid;
                        commodityHUD.CommodityId = commodityId;
                        commodityHUD.RoleTrans = _roleTran;
                        commodityHUD.IsSuperCustomer = isSuperCustomer;
                        duration = CityRealAiCSharpCallLuaManager.BindCommodityHUD(commodityHUD);
                        this.startAnimName = commodityHUD.StartAnimationName;
                        this.endAnimName = commodityHUD.EndAnimationName;
                        this.hideAnimName = commodityHUD.HideAnimationName;
                    }
                    TryShowHudAnimation();

                    _hudObj.transform.position = new Vector3(-1000f, -1000f, -1000f);
                    _hudObj.transform.localEulerAngles = new Vector3(45, -10, 0);
// #if UNITY_EDITOR
//                     _hudObj.name = $"duration = {duration} 时长的商品气泡";
// #endif
                    // if (duration > 0) // 时间到了自动消失
                    // {
                    //     Timers.inst.Add(duration, 1, OnDelayHideHud);
                    // }
                    // 屋顶显示时 / 已停止时 不显示气泡
                    bool isNotVisible = (CityRealAiManager.GetInstance().RoofShowState && CityRealAiManager.GetInstance().LimitShowState);
                    if (isNotVisible || _isStop)
                    {
                        if (_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(false);
                        }
                    }
                    else
                    {
                        if (!_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(true);
                        }
                    }
                });

                bubbleData.Reset();
            }
        }

        public override void OnHideHud()
        {
            PerformerUid = 0;
            if (_commodityHUD)
            {
                CityRealAiCSharpCallLuaManager.UnbindCommodityHUD(_commodityHUD);
            }
            base.OnHideHud();
        }
        
        protected override void DestroyHud()
        {
            _commodityHUD = null;
            base.DestroyHud();
        }
        
        
    }
    
    // 特效
    public class HudEffect : HudNpcBase
    {
        private CityRealHudBubbleData _nextBubbleData;

        public HudEffect(int uid, CityRealHudManager hudMgr, CityRealAiConfigManager cfgMgr) : base(uid, hudMgr, cfgMgr)
        {
        }

        public void OnChangeHud(int uid, Transform roleTran, string bubble, float displaytTime, int bone_bind)
        {
            _nextBubbleData.SetValue(uid, string.Format(CityRealAiConst.TriggerEffectPath, bubble), displaytTime, bone_bind);
            base.OnChangeHud(roleTran);
        }

        protected override void TryShowHud()
        {
            if (_nextBubbleData.inUse)
            {
                CityRealHudBubbleData bubbleData = _nextBubbleData;
                _nextBubbleData.Reset();
                if (bubbleData.bones_bind <= 0)
                {
                    // Debug.LogError(LogModule.CityAI, "尝试触发 OnShowBubble事件，但是配置 city_ai_event 中 bones_bind_bubble = 0");
                    return;
                }

                var cfg = _cfgMgr.GetBonePathConfig(bubbleData.bones_bind);
                if (cfg.id == _cfgMgr.EmptyBonePathCfg.id || string.IsNullOrEmpty(cfg.bone_path))
                {
                    // Debug.LogErrorFormat(LogModule.CityAI,
                    //     LogLevelType.Develop, "尝试触发 OnShowBubble事件，但是配置 city_ai_npc_bonepath 中未找到 id = {0} 的配置",
                    //     bubbleData.bones_bind);
                    return;
                }

                string bonePath = cfg.bone_path;
                _boneTran = _roleTran.Find(bonePath);
                if (_boneTran == null)
                {
                    bonePath = bonePath.Substring(bonePath.LastIndexOf("/") + 1);
                    if (string.Equals(bonePath, "Root"))
                    {
                        _boneTran = _roleTran;

                    }
                    else
                    {
                        _boneTran = _roleTran.Find(bonePath);
                    }
                }

                if (_boneTran == null)
                {
                    // Debug.LogErrorFormat(LogModule.CityAI,LogLevelType.Develop,
                    //     "尝试触发 OnShowEffect事件，但是模型中 未找到 BonePath = {0} 的节点", cfg.bone_path);
                    return;
                }

                _hudResPath = bubbleData.prefabPath;
                float duration = bubbleData.displayTime;
                IsInLoadHud = true;
                _hudMgr.GetHudObj(_hudResPath, _hudMgr.effectRoot, (hudObj) =>
                {
                    _hudObj = hudObj;
                    IsInLoadHud = false;
                   
                    _hudObj.transform.position = _boneTran.position;
#if UNITY_EDITOR
                    _hudObj.name = $"ui = {bubbleData.uid} eventId = {bubbleData.eventId} 产生的特效";
#endif
                    if (duration > 0) // 时间到了自动消失
                    {
                        Timers.inst.Add(duration, 1, OnDelayHideHud);
                    }
                    // 屋顶显示时 / 已停止时 不显示气泡
                    bool isNotVisible = (CityRealAiManager.GetInstance().RoofShowState && CityRealAiManager.GetInstance().LimitShowState);
                    if (isNotVisible || _isStop)
                    {
                        if (_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(false);
                        }
                    }
                    else
                    {
                        if (!_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(true);
                        }
                    }
                });

                bubbleData.Reset();
            }
        }

    }
    
    public class HudStaffBubble : HudNpcBase
    {
        private CityRealHudBubbleData _nextBubbleData;

        private string _hudSpriteName;

        public HudStaffBubble(int uid, CityRealHudManager hudMgr, CityRealAiConfigManager cfgMgr) : base(uid, hudMgr, cfgMgr)
        {
        }

        public GameObject GetHudObj()
        {
            return _hudObj;
        }
        public void OnChangeStaffBubble(int uid, string bubble, Transform roleTran, int bind_bone, int staffId)
        {
            _nextBubbleData.SetValue(uid, string.Format(CityRealAiConst.BubblePath, bubble), 0, bind_bone,0,bubble,staffId);
            OnChangeHud(roleTran);
        }
        protected override void OnChangeHud(Transform roleTran)
        {
            _roleTran = roleTran;

            if (IsExistHud)
            {
                DestroyHud();
                TryShowHud();
            }
            else
            {
                TryShowHud();
            }
        }

        protected override void TryShowHud()
        {
            if (_nextBubbleData.inUse)
            {
                CityRealHudBubbleData bubbleData = _nextBubbleData;
                _nextBubbleData.Reset();
                if (bubbleData.bones_bind <= 0)
                {
                    Debug.LogError(LogModule.CityAI, "尝试显示雇佣气泡 但bones_bind_bubble = 0");
                    return;
                }

                var cfg = _cfgMgr.GetBonePathConfig(bubbleData.bones_bind);
                if (cfg.id == _cfgMgr.EmptyBonePathCfg.id || string.IsNullOrEmpty(cfg.bone_path))
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示雇佣气泡，但是配置 city_ai_npc_bonepath 中未找到 id = {0} 的配置", bubbleData.bones_bind);
                    return;
                }

                string bonePath = cfg.bone_path;
                _boneTran = _roleTran.Find(bonePath);
                if (_boneTran == null)
                {
                    bonePath = bonePath.Substring(bonePath.LastIndexOf("/") + 1);
                    if (string.Equals(bonePath, "Root"))
                    {
                        _boneTran = _roleTran;
                    }
                    else
                    {
                        _boneTran = _roleTran.Find(bonePath);
                    }
                }

                if (_boneTran == null)
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示雇佣气泡，但是模型中 未找到 BonePath = {0} 的节点", cfg.bone_path);
                    return;
                }

                int uid = bubbleData.uid;
                int staffId = bubbleData.param2;
                string hudSprite = bubbleData.stringParam;
                _hudResPath = bubbleData.prefabPath;
                IsInLoadHud = true;
                _hudMgr.GetHudObj(_hudResPath, _hudMgr.hudRoot, (hudObj) =>
                {
                    _hudObj = hudObj;
                    _hudCollider = hudObj.GetComponentInChildren<BoxCollider>();
                    IsInLoadHud = false;
                    float duration = 0;
                    CityRealAiStaffHUD staffHUD = _hudObj.GetComponent<CityRealAiStaffHUD>();
                    if (staffHUD)
                    {
                        staffHUD.Uid = uid;
                        staffHUD.StaffId = staffId;
                        staffHUD.RoleTrans = _roleTran;
                        duration = CityRealAiCSharpCallLuaManager.BindStaffHUD(staffHUD);
                        this.startAnimName = staffHUD.StartAnimationName;
                        this.endAnimName = staffHUD.EndAnimationName;
                        this.hideAnimName = staffHUD.HideAnimationName;
                    }

                    TryShowHudAnimation();
                    
                    
                    _hudObj.transform.position = new Vector3(-1000f, -1000f, -1000f);
                    _hudObj.transform.localEulerAngles = new Vector3(45, -10, 0);
#if UNITY_EDITOR
                    _hudObj.name = $"StaffId = {staffId} 的雇佣气泡";
#endif
                    if (duration > 0) // 时间到了自动消失
                    {
                        Timers.inst.Add(duration, 1, OnDelayHideHud);
                    }
                    // 屋顶显示时 / 已停止时 不显示气泡
                    bool isNotVisible = (CityRealAiManager.GetInstance().RoofShowState && CityRealAiManager.GetInstance().LimitShowState);
                    if (isNotVisible || _isStop)
                    {
                        if (_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(false);
                        }
                    }
                    else
                    {
                        if (!_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(true);
                        }
                    }
                });

                bubbleData.Reset();
            }
        }

        public override void OnHideHud()
        {

            if (_hudObj != null)
            {
                var ani = _hudObj.GetComponent<Animation>();
                if (ani == null)
                {
                    DestroyHud();
                }
                else
                {
                    if (!string.IsNullOrEmpty(this.endAnimName))
                    {
                        
                        ani.Play(this.endAnimName);
                    }
                    else
                    {
                        DestroyHud();
                    }
                }
            }
            else
            {
                TryShowHud();
            }
        }

        public void DestroyHudShow()
        {
            DestroyHud();
        }
        
        protected override void DestroyHud()
        {
            base.DestroyHud();
        }
    }
    
    public class HudBabeMoodBubble : HudNpcBase
    {
        private CityRealHudBubbleData _nextBubbleData;

        private CityRealAiBabeMoodHUD _babeMoodHUD;

        private string _hudSpriteName;

        public HudBabeMoodBubble(int uid, CityRealHudManager hudMgr, CityRealAiConfigManager cfgMgr) : base(uid, hudMgr, cfgMgr)
        {
        }

        public GameObject GetHudObj()
        {
            return _hudObj;
        }
        public void OnChangeBabeMoodBubble(int uid, string bubble, Transform roleTran, int bind_bone, int resId)
        {
            _nextBubbleData.SetValue(uid, string.Format(CityRealAiConst.BubblePath, bubble), 0, bind_bone,0,bubble,resId);
            OnChangeHud(roleTran);
        }
        protected override void OnChangeHud(Transform roleTran)
        {
            _roleTran = roleTran;

            if (IsExistHud)
            {
                DestroyHud();
                TryShowHud();
            }
            else
            {
                TryShowHud();
            }
        }

        protected override void TryShowHud()
        {
            if (_nextBubbleData.inUse)
            {
                CityRealHudBubbleData bubbleData = _nextBubbleData;
                _nextBubbleData.Reset();
                if (bubbleData.bones_bind <= 0)
                {
                    Debug.LogError(LogModule.CityAI, "尝试显示美女资源气泡 但bones_bind_bubble = 0");
                    return;
                }

                var cfg = _cfgMgr.GetBonePathConfig(bubbleData.bones_bind);
                if (cfg.id == _cfgMgr.EmptyBonePathCfg.id || string.IsNullOrEmpty(cfg.bone_path))
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示雇佣气泡，但是配置 city_ai_npc_bonepath 中未找到 id = {0} 的配置", bubbleData.bones_bind);
                    return;
                }

                string bonePath = cfg.bone_path;
                _boneTran = _roleTran.Find(bonePath);
                if (_boneTran == null)
                {
                    bonePath = bonePath.Substring(bonePath.LastIndexOf("/") + 1);
                    if (string.Equals(bonePath, "Root"))
                    {
                        _boneTran = _roleTran;
                    }
                    else
                    {
                        _boneTran = _roleTran.Find(bonePath);
                    }
                }

                if (_boneTran == null)
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示雇佣气泡，但是模型中 未找到 BonePath = {0} 的节点", cfg.bone_path);
                    return;
                }

                int uid = bubbleData.uid;
                int resId = bubbleData.param2;
                string hudSprite = bubbleData.stringParam;
                _hudResPath = bubbleData.prefabPath;
                IsInLoadHud = true;
                _hudMgr.GetHudObj(_hudResPath, _hudMgr.hudRoot, (hudObj) =>
                {
                    _hudObj = hudObj;
                    _hudCollider = hudObj.GetComponentInChildren<BoxCollider>();
                    IsInLoadHud = false;
                    float duration = -1;
                    CityRealAiBabeMoodHUD babeMoodHUD = _hudObj.GetComponent<CityRealAiBabeMoodHUD>();
                    _babeMoodHUD = babeMoodHUD;
                    if (babeMoodHUD)
                    {
                        babeMoodHUD.Uid = uid;
                        babeMoodHUD.ResId = resId;
                        babeMoodHUD.RoleTrans = _roleTran;
                        CityRealAiCSharpCallLuaManager.BindBabeMoodHUD(babeMoodHUD);
                        this.startAnimName = babeMoodHUD.StartAnimationName;
                        this.endAnimName = babeMoodHUD.EndAnimationName;
                        this.hideAnimName = babeMoodHUD.HideAnimationName;
                    }

                    TryShowHudAnimation();
                    
                    
                    _hudObj.transform.position = new Vector3(-1000f, -1000f, -1000f);
                    _hudObj.transform.localEulerAngles = new Vector3(45, -10, 0);
#if UNITY_EDITOR
                    _hudObj.name = $"ResId = {resId} 的美女资源气泡";
#endif
                    if (duration > 0) // 时间到了自动消失
                    {
                        Timers.inst.Add(duration, 1, OnDelayHideHud);
                    }
                    // 屋顶显示时 / 已停止时 不显示气泡
                    bool isNotVisible = (CityRealAiManager.GetInstance().RoofShowState && CityRealAiManager.GetInstance().LimitShowState);
                    if (isNotVisible || _isStop)
                    {
                        if (_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(false);
                        }
                    }
                    else
                    {
                        if (!_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(true);
                        }
                    }
                });

                bubbleData.Reset();
            }
        }

        public override void OnHideHud()
        {
            if (_babeMoodHUD)
            {
                CityRealAiCSharpCallLuaManager.UnbindBabeMoodHUD(_babeMoodHUD);
            }
            if (_hudObj != null)
            {
                var ani = _hudObj.GetComponent<Animation>();
                if (ani == null)
                {
                    DestroyHud();
                }
                else
                {
                    if (!string.IsNullOrEmpty(this.endAnimName))
                    {
                        
                        ani.Play(this.endAnimName);
                    }
                    else
                    {
                        DestroyHud();
                    }
                }
            }
            else
            {
                TryShowHud();
            }
        }

        public void DestroyHudShow()
        {
            DestroyHud();
        }
        
        protected override void DestroyHud()
        {
            base.DestroyHud();
        }
    }
    
    public class HudDialogueBubble : HudNpcBase
    {
        private CityRealHudBubbleData _nextBubbleData;

        public HudDialogueBubble(int uid, CityRealHudManager hudMgr, CityRealAiConfigManager cfgMgr) : base(uid, hudMgr, cfgMgr)
        {
        }

        public GameObject GetHudObj()
        {
            return _hudObj;
        }
        public void OnChangeDialogueBubble(int uid, string bubble, Transform roleTran, int bind_bone, int areaId, float displaytTime)
        {
            _nextBubbleData.SetValue(uid, string.Format(CityRealAiConst.BubblePath, bubble), displaytTime, bind_bone,0,bubble,areaId);
            OnChangeHud(roleTran);
        }
        protected override void OnChangeHud(Transform roleTran)
        {
            _roleTran = roleTran;

            if (IsExistHud)
            {
                DestroyHud();
                TryShowHud();
            }
            else
            {
                TryShowHud();
            }
        }

        protected override void TryShowHud()
        {
            if (_nextBubbleData.inUse)
            {
                CityRealHudBubbleData bubbleData = _nextBubbleData;
                _nextBubbleData.Reset();
                if (bubbleData.bones_bind <= 0)
                {
                    Debug.LogError(LogModule.CityAI, "尝试显示对话气泡 但bones_bind_bubble = 0");
                    return;
                }

                var cfg = _cfgMgr.GetBonePathConfig(bubbleData.bones_bind);
                if (cfg.id == _cfgMgr.EmptyBonePathCfg.id || string.IsNullOrEmpty(cfg.bone_path))
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示雇佣气泡，但是配置 city_ai_npc_bonepath 中未找到 id = {0} 的配置", bubbleData.bones_bind);
                    return;
                }

                string bonePath = cfg.bone_path;
                _boneTran = _roleTran.Find(bonePath);
                if (_boneTran == null)
                {
                    bonePath = bonePath.Substring(bonePath.LastIndexOf("/") + 1);
                    if (string.Equals(bonePath, "Root"))
                    {
                        _boneTran = _roleTran;
                    }
                    else
                    {
                        _boneTran = _roleTran.Find(bonePath);
                    }
                }

                if (_boneTran == null)
                {
                    // Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop,
                    //     "尝试触发 显示雇佣气泡，但是模型中 未找到 BonePath = {0} 的节点", cfg.bone_path);
                    return;
                }

                int uid = bubbleData.uid;
                int areaId = bubbleData.param2;
                float duration = bubbleData.displayTime;
                string hudSprite = bubbleData.stringParam;
                _hudResPath = bubbleData.prefabPath;
                IsInLoadHud = true;
                _hudMgr.GetHudObj(_hudResPath, _hudMgr.hudRoot, (hudObj) =>
                {
                    _hudObj = hudObj;
                    _hudCollider = hudObj.GetComponentInChildren<BoxCollider>();
                    IsInLoadHud = false;
                    CityRealAiDialogueHUD dialogueHUD = _hudObj.GetComponent<CityRealAiDialogueHUD>();
                    if (dialogueHUD)
                    {
                        dialogueHUD.Uid = uid;
                        dialogueHUD.DialogueContent.text = CityRealAiCSharpCallLuaManager.RandomDialogueContent(areaId);
                        
                        dialogueHUD.BubbleRect.SetWidth(dialogueHUD.DialogueContent.preferredWidth);
                    }

                    TryShowHudAnimation();
                    
                    
                    _hudObj.transform.position = new Vector3(-1000f, -1000f, -1000f);
                    _hudObj.transform.localEulerAngles = new Vector3(45, -10, 0);
#if UNITY_EDITOR
                    _hudObj.name = $"AreaId = {areaId} 的对话气泡";
#endif
                    if (duration > 0) // 时间到了自动消失
                    {
                        Timers.inst.Add(duration, 1, OnDelayHideHud);
                    }
                    // 屋顶显示时 / 已停止时 不显示气泡
                    bool isNotVisible = (CityRealAiManager.GetInstance().RoofShowState && CityRealAiManager.GetInstance().LimitShowState);
                    if (isNotVisible || _isStop)
                    {
                        if (_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(false);
                        }
                    }
                    else
                    {
                        if (!_hudObj.activeSelf)
                        {
                            _hudObj.SetActive(true);
                        }
                    }
                });

                bubbleData.Reset();
            }
        }

        public override void OnHideHud()
        {

            if (_hudObj != null)
            {
                var ani = _hudObj.GetComponent<Animation>();
                if (ani == null)
                {
                    DestroyHud();
                }
                else
                {
                    if (!string.IsNullOrEmpty(this.endAnimName))
                    {
                        
                        ani.Play(this.endAnimName);
                    }
                    else
                    {
                        DestroyHud();
                    }
                }
            }
            else
            {
                TryShowHud();
            }
        }

        public void DestroyHudShow()
        {
            DestroyHud();
        }
        
        protected override void DestroyHud()
        {
            base.DestroyHud();
        }
    }
    
}
